// 增加一个call_once的例子
#include <mutex>
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>

// 如何使用一个call once能
//  1. 确保某个函数只被调用一次
//  2. 确保某个变量只被初始化一次
// 比如一个初始化 然后在多线程中
// 我不用关于谁调用 反正只能调用一次
// 就是每一个都是完整的一套 然后如果里面有单独的就用这部分单独处理

std::once_flag flag;

void do_once()
{
    std::call_once(flag, []()
                   { std::cout << "do_once" << std::endl; });
}

// int main()
// {
//     std::thread t1(do_once);
//     std::thread t2(do_once);
//     std::thread t3(do_once);
//     std::thread t4(do_once);
//     t1.join();
//     t2.join();
//     t3.join();
//     t4.join();
//     return 0;
// }

// 数据库连接池示例
class DatabaseConnectionPool
{
private:
    static std::once_flag init_flag;
    static std::vector<std::string> connections;

    static void initialize()
    {
        std::cout << "正在初始化数据库连接池..." << std::endl;
        // 模拟创建数据库连接的耗时操作
        std::this_thread::sleep_for(std::chrono::seconds(2));

        // 初始化连接池
        connections.push_back("Connection-1");
        connections.push_back("Connection-2");
        connections.push_back("Connection-3");

        std::cout << "数据库连接池初始化完成！" << std::endl;
    }

public:
    static void getConnection(int threadId)
    {
        // 确保连接池只被初始化一次
        std::call_once(init_flag, initialize);

        // 模拟使用连接
        std::cout << "线程 " << threadId << " 正在使用连接: "
                  << connections[threadId % connections.size()] << std::endl;
    }
};

// 静态成员初始化
std::once_flag DatabaseConnectionPool::init_flag;
std::vector<std::string> DatabaseConnectionPool::connections;

void workerThread(int id)
{
    std::cout << "线程 " << id << " 开始执行" << std::endl;
    DatabaseConnectionPool::getConnection(id);
}

// 第二个main函数，用于演示数据库连接池
int main_db_example()
{
    std::vector<std::thread> threads;

    // 创建多个线程同时尝试访问数据库连接池
    for (int i = 0; i < 5; i++)
    {
        threads.push_back(std::thread(workerThread, i));
    }

    // 等待所有线程完成
    for (auto &thread : threads)
    {
        thread.join();
    }

    return 0;
}
